﻿package com.d4p.iterator
{
	import com.d4p.util.Operator;
	
	public class Collection implements IFCollection
	{	
		static public const ITERATOR_FORWARD:int = new int(1);
		static public const ITERATOR_REVERSE:int = new int(-1);
		static public const ITERATOR_NULL:int = new int(0);
		
		private  var __list:Array 
		//private
 
		public function Collection(list:* = null):void{
			if(list == null){
				 this.clear();
			}else{
				this.initialize(list);
			}
		}
		
		public function getList():Array{
			return this.__list;
		}
		
		private function initialize(list:*):void{
			if(list is Array){
				this.__list = (list as Array).concat();
			}else if(list is Collection){
				this.__list = Collection(list).__list.concat();
			}else{
				this.clear();	
			}
		}
		
		public function concat(...args:*):IFCollection{
			var result:Collection = new Collection(this);
			if(args.length == 1){
				if(args[0] is Array){
					result.__list = result.__list.concat((args as Array)[0]);
					
				}else if(args[0] is Collection){
					result.__list = result.__list.concat(Collection(args[0]).__list);
				}
				
			}else if(args.length > 1){
				result.__list = result.__list.concat(args);
			}
			return result;			
		}
		
		public function getIterator(dir:int = 1):IFIterator
		{
			var result:IFIterator
			if(dir > ITERATOR_NULL){
				result = new CollectionIterator(this);
				
			}else if(dir < ITERATOR_NULL){
				result = new CollectionReverseIterator(this);
			}else{
				result = new NULLIterator();
			}
			return result;
				
		}
		
		public function clear():void{
			this.__list = new Array();
		}
		
		public function addItem(item:*):Boolean{
			if(this.contains(item)) return false;
			return Boolean( this.push(item));
		}
		
		public function replaceWith(item:*, idx:uint):int{
			removeItemAt(idx);
			return addItemAt(item, idx);
		}
		
		public function removeItem(item:*):Boolean{
			var idx:int = this.getIndex(item);
			if(idx <0) return false;
			return Boolean(this.removeItemAt(idx));
		}
		
		public function contains(item:*):Boolean{
			if(this.__list.indexOf(item) >= 0) return true;
			return false;
		}
		
		public function isEmpty():Boolean{
			return Boolean(this.getLength());
		}
		
		public function getItemAt(idx:uint):*{
			return this.__list[idx];
			
		}
		
		public function getLength():uint{
			return this.__list.length;
		}
		
		public function getIndex(item:*):int{
			return this.__list.indexOf(item);
		}
		
		public function removeItemAt(idx:uint):*{
			if(idx > this.getLength()-1) return null;
			return this.__list.splice(idx,1)[0];
		}
		
		public function suffle():void{
			var src:IFCollection = this.concat();
			this.clear();
			while(src.getLength()){
				var idx:uint = Operator.randomUint(0, src.getLength()-1);
				var item:* = src.removeItemAt(idx);
				this.push(item);
			}
		}
		
		public function push(...args:*):uint{
			return this.__list.push.apply(null, args);
		}
		
		public function pop():*{
			return this.__list.pop();
		}
		
		public function shift():*{
			return this.__list.shift();
		}
		
		public function unshift(...args:*):uint{
			return this.__list.unshift.apply(null, args);
		}
		
		public function bringToFront(item:*):Boolean{
			var idx:int = this.getIndex(item);
			if(idx <0) return false;
			return Boolean(this.unshift(this.removeItemAt(idx)));
		}
		
		public function sendToBack(item:*):Boolean{
			var idx:int = this.getIndex(item);
			if(idx < 0) return false;
			return Boolean(this.push(this.removeItemAt(idx)));
		}
		
		public function rotateForward(item:*=null, idx:uint=0):void{
			if(this.contains(item)== false || idx > this.getLength()-1){
				this.unshift(this.pop());	
			}else{
				while(item != this.getItemAt(idx)){
					this.unshift(this.pop());
				}
			}
		}
		
		public function rotateRewind(item:*=null , idx:uint=0):void{
			if(this.contains(item) == false || idx > this.getLength()-1){
				this.push(this.shift());
			}else{
				while(item !=this.getItemAt(idx)){
					this.push(this.shift());							
				}
			}
		}
		
		public function reverse():void{
			this.__list.reverse();
		}
		
		public function addItemAt(item:*, idx:uint):int{
			if(idx > this.getLength()) return -1;
			if(this.contains(item)) return -1;
			this.__list.splice(idx,0,item);
			return this.getLength();
		}
		
		public function split(item:* ):Object{
			var idx:int = this.getIndex(item);
			var result:Object = new Object();
			result.prev = new Collection( this.__list.slice(0, idx));
			result.target = new Collection([item])
			result.next = new Collection( this.__list.slice(idx+1));
			return  result
		}
		
		
		public function toString():String{
			
			var msg:String = new String();
			msg += "-- list.Collection -- \r"
			msg += this.__list.valueOf()+ "\r";
			msg += "length : " + this.getLength() + "\r";
			msg += "---------------------"
			return msg;	
		}
		
		public function removeSameItem():void{
			var src:Collection = Collection(this.concat());
			this.clear();
			var it:IFIterator = src.getIterator();
			while(it.hasNext()){
				this.addItem(it.next());
			}
		}
	}
}